package driver

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"os"
	"sync"

	goonvif "github.com/use-go/onvif"
	"github.com/use-go/onvif/media"
	mediasdk "github.com/use-go/onvif/sdk/media"
	"k8s.io/klog/v2"
)

func NewClient(protocol ProtocolConfig) (*CustomizedClient, error) {
	client := &CustomizedClient{
		ProtocolConfig: protocol,
		deviceMutex:    sync.Mutex{},
		// TODO initialize the variables you added
	}
	return client, nil
}

func (c *CustomizedClient) InitDevice() error {
	// you can use c.ProtocolConfig
	// Through this function, the onvif device variable can be generated by ProtocolConfig.
	password, err := readPassword(c.ProtocolConfig.Password) // get device password
	if err != nil {
		return err
	}

	deviceParams := goonvif.DeviceParams{
		Xaddr:      c.ProtocolConfig.URL,
		Username:   c.ProtocolConfig.UserName,
		Password:   password,
		HttpClient: new(http.Client),
	}

	dev, err := goonvif.NewDevice(deviceParams) //build onvif device according to use-go/onvif
	if err != nil {
		return err
	}
	c.dev = dev
	return nil

}

func (c *CustomizedClient) GetDeviceData(visitor *VisitorConfig) (interface{}, error) {
	// you can use c.ProtocolConfig and visitor
	// Through this function, the authentication file and RTSP URI of the onvif device will be returned.
	ctx := context.Background()
	if c.dev == nil {
		return nil, fmt.Errorf("device does not exist")
	}

	// get onvif device ProfilesToken
	getProfiles := media.GetProfiles{}
	profilesResp, err := mediasdk.Call_GetProfiles(ctx, c.dev, getProfiles)
	if err != nil {
		klog.Error(err)
		return nil, err
	} else if len(profilesResp.Profiles) == 0 {
		return "", fmt.Errorf("no onvif profiles found")
	}
	token := profilesResp.Profiles[0].Token

	// get onvif device RTSP Stream Uri with ProfilesToken
	getStreamUri := media.GetStreamUri{
		ProfileToken: token,
	}
	uriResp, err := mediasdk.Call_GetStreamUri(ctx, c.dev, getStreamUri)
	if err != nil {
		return "", fmt.Errorf("GetStreamURI failed: %v", err.Error())
	}
	return string(uriResp.MediaUri.Uri), nil
}

func (c *CustomizedClient) SetDeviceData(data interface{}, visitor *VisitorConfig) error {
	// TODO: set device's data, such as controlling the position and posture of the camera, will be added in subsequent versions
	// you can use c.ProtocolConfig and visitor
	klog.V(2).Infof("still wait to complete setdevicedata feature")
	return nil
}

func (c *CustomizedClient) StopDevice() error {
	// stop device
	// you can use c.ProtocolConfig
	klog.Info("Stop onvif device successfully")
	return nil
}

func readPassword(filename string) (string, error) {
	b, err := os.ReadFile(filename)
	if err != nil {
		return "", errors.New("Failed to load certificate")
	}
	// Remove the last character '\n'
	return string(b[:len(b)-1]), nil
}
